package com.dyava.commons.lock.local;
import com.dyava.commons.lock.KeyLock;
import com.dyava.commons.lock.KeyLockException;
import com.dyava.commons.lock.KeyLockTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class LocalKeyLock implements KeyLock {
    static Logger log = LoggerFactory.getLogger(LocalKeyLock.class);

    String key;
    ReentrantLock reentrantLock;
    LocalKeyLockPool factory;
    boolean locked;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public LocalKeyLock(LocalKeyLockPool factory, String key, ReentrantLock reentrantLock) {
        this.factory = factory;
        this.key = key;
        this.reentrantLock = reentrantLock;
    }

    public boolean tryLock(){
        if(locked){
            throw new KeyLockException("不可重复锁定");
        }
        boolean res =  reentrantLock.tryLock();
        if(res){
            locked=true;
            log.trace(Thread.currentThread()+"{} -> try 成功",key);
        }else{
            log.trace(Thread.currentThread()+"{} -> try 失败",key);
        }
        return res;
    }

    public void lock( int maxWaitTime){
        if(locked){
            throw new KeyLockException("不可重复锁定");
        }
        try {
            boolean res = reentrantLock.tryLock(maxWaitTime, TimeUnit.MILLISECONDS);
            if(res){
                locked=true;
                log.trace(Thread.currentThread()+"{} -> lock 成功",key);
            }else{
                log.trace(Thread.currentThread()+"{} -> lock 失败",key);
                throw new KeyLockTimeoutException("lock 超时");
            }
        } catch (InterruptedException e) {
            throw new KeyLockException(e);
        }
    }


    @Override
    public void close(){
        if(locked) {
            log.trace("{} -> 释放锁",key);
            reentrantLock.unlock();
            locked=false;
        }
        if(reentrantLock!=null){
            factory.tryReleaseLock(this);
            reentrantLock=null;
        }
    }
}
